/* The lexical analyzer for Nyu programming language.
 */

%{

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nyu_tree.h"
#include "parse.h"

#define YY_DECL int yylex(YYSTYPE *lv)

/* 警告を避ける */
#define ECHO /* do nothing */
#define YY_NO_INPUT

%}

%option noyywrap
%option nounput
%option nostack
%option yylineno

DECINT_LITERAL       [0-9]+
HEXINT_LITERAL       0x[0-9a-fA-F]+
OCTINT_LITERAL       0[0-7]+
BITINT_LITERAL       0b[01]+
FLOAT_LITERAL        ([0-9]*\.[0-9]+([eE][\+-]?[0-9]+)?|[0-9]+([eE][\+-]?[0-9]+))

SYMBOL               [a-zA-Z_][a-zA-Z0-9_]*

%x QSTRING
%x QQSTRING

%%

"=" {
    return NYU_TOK_EQUAL;
}

"==" {
    return NYU_TOK_EQUAL2;
}

"===" {
    return NYU_TOK_EQUAL3;
}

"!" {
    return NYU_TOK_EXCLAMATION;
}

"!=" {
    return NYU_TOK_EXCLAMATION_EQUAL;
}

"!==" {
    return NYU_TOK_EXCLAMATION_EQUAL2;
}

"+" {
    return NYU_TOK_PLUS;
}

"++" {
    return NYU_TOK_PLUS2;
}

"+=" {
    return NYU_TOK_PLUS_EQUAL;
}

"-" {
    return NYU_TOK_MINUS;
}

"--" {
    return NYU_TOK_MINUS2;
}

"-=" {
    return NYU_TOK_MINUS_EQUAL;
}

"*" {
    return NYU_TOK_ASTERISK;
}

"*=" {
    return NYU_TOK_ASTERISK_EQUAL;
}

"/" {
    return NYU_TOK_SLASH;
}

"/=" {
    return NYU_TOK_SLASH_EQUAL;
}

"%" {
    return NYU_TOK_PERCENT;
}

"%=" {
    return NYU_TOK_PERCENT_EQUAL;
}

"<" {
    return NYU_TOK_LESS;
}

"<<" {
    return NYU_TOK_LESS2;
}

"<=" {
    return NYU_TOK_LESS_EQUAL;
}

"<<=" {
    return NYU_TOK_LESS2_EQUAL;
}

">" {
    return NYU_TOK_GREATER;
}

">>" {
    return NYU_TOK_GREATER2;
}

">=" {
    return NYU_TOK_GREATER_EQUAL;
}

">>=" {
    return NYU_TOK_GREATER2_EQUAL;
}

"<=>" {
    return NYU_TOK_LESS_EQUAL_GREATER;
}

"<->" {
    return NYU_TOK_LESS_MINUS_GREATER;
}

"|" {
    return NYU_TOK_PIPE;
}

"||" {
    return NYU_TOK_PIPE2;
}

"|=" {
    return NYU_TOK_PIPE_EQUAL;
}

"||=" {
    return NYU_TOK_PIPE2_EQUAL;
}

"^" {
    return NYU_TOK_HAT;
}

"^^" {
    return NYU_TOK_HAT2;
}

"^=" {
    return NYU_TOK_HAT_EQUAL;
}

"&" {
    return NYU_TOK_AMPERSAND;
}

"&&" {
    return NYU_TOK_AMPERSAND2;
}

"&=" {
    return NYU_TOK_AMPERSAND_EQUAL;
}

"&&=" {
    return NYU_TOK_AMPERSAND2_EQUAL;
}

"~" {
    return NYU_TOK_TILDE;
}

"~~" {
    return NYU_TOK_TILDE2;
}

"?" {
    return NYU_TOK_QUESTION;
}

":" {
    return NYU_TOK_COLON;
}

":=" {
    return NYU_TOK_COLON_EQUAL;
}

";" {
    return NYU_TOK_SEMICOLON;
}

"." {
    return NYU_TOK_DOT;
}

".." {
    return NYU_TOK_DOT2;
}

"..." {
    return NYU_TOK_DOT3;
}

"," {
    return NYU_TOK_COMMA;
}

"(" {
    return NYU_TOK_LPARENTHESIS;
}

")" {
    return NYU_TOK_RPARENTHESIS;
}

"[" {
    return NYU_TOK_LBRACKET;
}

"]" {
    return NYU_TOK_RBRACKET;
}

"{" {
    return NYU_TOK_LBRACE;
}

"}" {
    return NYU_TOK_RBRACE;
}

"{%" {
    return NYU_TOK_LBRACE_PERCENT;
}

"%}" {
    return NYU_TOK_PERCENT_RBRACE;
}


{BITINT_LITERAL} {
    lv->intval = strtol(yytext + 2, NULL, 2);
    return NYU_TOK_INTVAL;
}

{HEXINT_LITERAL} {
    lv->intval = strtol(yytext, NULL, 16);
    return NYU_TOK_INTVAL;
}

{OCTINT_LITERAL} {
    lv->intval = strtol(yytext, NULL, 8);
    return NYU_TOK_INTVAL;
}

{DECINT_LITERAL} {
    lv->intval = strtol(yytext, NULL, 10);
    return NYU_TOK_INTVAL;
}

{FLOAT_LITERAL} {
    lv->fltval = strtod(yytext, NULL);
    return NYU_TOK_FLTVAL;
}

{SYMBOL} {
    lv->strval = strdup(yytext);
    return NYU_TOK_SYMBOL;
}

\$[0-9]+ {
    lv->intval = strtol(yytext + 1, NULL, 10);
    return NYU_TOK_ARGREF;
}

\$\# {
    return NYU_TOK_ARGLEN;
}

\$\@ {
    return NYU_TOK_CURBLK;
}


\' {
    lv->strval = (char *)malloc(1);
    lv->strval[0] = '\0';
    BEGIN(QSTRING);
}
<QSTRING>[^\']+ {
    lv->strval = (char *)realloc(lv->strval, strlen(lv->strval) + yyleng + 1);
    strncat(lv->strval, yytext, yyleng);
}
<QSTRING>\'\' {
    size_t len = strlen(lv->strval);
    lv->strval = (char *)realloc(lv->strval, len + 1 + 1);
    lv->strval[len] = '\'';
    lv->strval[len + 1] = '\0';
}
<QSTRING><<EOF>> {
    /* error */
    BEGIN(INITIAL);
    return NYU_TOK_STRVAL;
}
<QSTRING>\' {
    BEGIN(INITIAL);
    return NYU_TOK_STRVAL;
}


\" {
    lv->strval = (char *)malloc(1);
    lv->strval[0] = '\0';
    BEGIN(QQSTRING);
}
<QQSTRING>[^\\\"]+ {
    lv->strval = (char *)realloc(lv->strval, strlen(lv->strval) + yyleng + 1);
    strncat(lv->strval, yytext, yyleng);
}
<QQSTRING>\\[0-7]{1,3} {
    int val = strtol(yytext+1, NULL, 8);
    size_t len = strlen(lv->strval);
    lv->strval = (char *)realloc(lv->strval, len + 1 + 1);
    lv->strval[len] = (char)val;
    lv->strval[len+1] = '\0';
}
<QQSTRING>\\[0-9]+ {
    /* invalid octal escape */
    lv->strval = (char *)realloc(lv->strval, strlen(lv->strval) + yyleng);
    strncat(lv->strval, yytext + 1, yyleng - 1);
}
<QQSTRING>\\(.|\n) {
    size_t len = strlen(lv->strval);
    lv->strval = (char *)realloc(lv->strval, len + 1 + 1);
    switch (yytext[yyleng - 1])
    {
    case 'b':
        lv->strval[len] = '\b';  
        break;
    case 't':
        lv->strval[len] = '\t';
        break;
    case 'n':
        lv->strval[len] = '\n';
        break;
    case 'v':
        lv->strval[len] = '\v';
        break;
    case 'f':
        lv->strval[len] = '\f';
        break;
    case 'r':
        lv->strval[len] = '\r';
        break;
    default:
        lv->strval[len] = yytext[yyleng - 1];
    }
    lv->strval[len + 1] = '\0';
}
<QQSTRING><<EOF>> {
    /* error */
    BEGIN(INITIAL);
    return NYU_TOK_STRVAL;
}
<QQSTRING>\" {
    BEGIN(INITIAL);
    return NYU_TOK_STRVAL;
}


"#".* {
    /* do nothing */
}

" "|\t|\n {
    /* do nothing */
}

. {
    fprintf(stderr, "Invalid charactor '%c' at line %d\n", yytext[0], yylineno);
    return NYU_TOK_ERROR;
}

%%
